using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace csammisrun.MsnLib
{
  /// <summary>
  /// Describes the type of an MSN Object
  /// </summary>
  public enum MsnObjectType
  {
    /// <summary>
    /// Unknown type
    /// </summary>
    Unknown = -1,
    /// <summary>
    /// Reserved value
    /// </summary>
    Reserved1 = 1,
    /// <summary>
    /// A custom MSN emoticon
    /// </summary>
    Emoticon = 2,
    /// <summary>
    /// An icon that represents the user
    /// </summary>
    UserImage = 3,
    /// <summary>
    /// Reserved value
    /// </summary>
    Reserved2 = 4,
    /// <summary>
    /// A background image
    /// </summary>
    Background = 5
  }

  public class MsnObject
  {
    private string _sha1d = "";
    private string _sha1c = "";
    private MsnObjectType _type = MsnObjectType.Unknown;
    private string _location = "";
    private string _reallocation = "";
    private string _friendly = "AAA=";

    private string _creator = null;
    private int _size = 0;

    /// <summary>
    /// Create a new MsnObject
    /// </summary>
    /// <param name="creator">The creator (owner) of the object</param>
    /// <param name="type">The <see cref="MsnObjectType"/> of the object</param>
    /// <param name="filename">The filename of the object</param>
    public MsnObject(User creator, MsnObjectType type)
    {
      _creator = creator.Passport;
      _type = type;
    }

    /// <summary>
    /// Create a new MsnObject from an MSN object content string
    /// </summary>
    /// <param name="contentstring"></param>
    /// <exception cref="ArgumentException">Thrown when contentstring is not a complete &lt;msnobject /&gt; tag</exception>
    public MsnObject(string contentstring)
    {
      if (!contentstring.ToLower().StartsWith("<msnobj"))
      {
        throw new ArgumentException("contentstring is not an <msnobj /> tag");
      }

      int typeint = 0;
      _creator = GetStringValue(contentstring, "Creator");
      _size = GetIntValue(contentstring, "Size");
      typeint = GetIntValue(contentstring, "Type");
      _location = GetStringValue(contentstring, "Location");
      _friendly = GetStringValue(contentstring, "Friendly");
      _sha1c = GetStringValue(contentstring, "SHA1C");
      _sha1d = GetStringValue(contentstring, "SHA1D");

      if (_creator == null || _size == 0 || typeint == 0 ||
        _location == "" || _friendly == "" || _sha1c == "" || _sha1d == "")
      {
        throw new ArgumentException("contentstring did not contain all the required fields");
      }

      _type = (MsnObjectType)typeint;
    }

    internal static int GetIntValue(string tag, string field)
    {
      int retval = 0;
      Int32.TryParse(GetStringValue(tag, field), out retval);
      return retval;
    }

    internal static string GetStringValue(string tag, string field)
    {
      int startindex = tag.IndexOf(field + "=\"") + field.Length + 2;
      int endindex = tag.IndexOf("\"", startindex);
      return tag.Substring(startindex, endindex - startindex);
    }

    #region Properties
    public string Creator
    {
      get { return _creator; }
    }

    public string Location
    {
      get { return _location; }
      set { _location = value; }
    }

    public string RealLocation
    {
      get { return _reallocation; }
      set { _reallocation = value; }
    }

    public string Friendly
    {
      get { return _friendly; }
      set { _friendly = value; }
    }

    /// <summary>
    /// Gets or sets the type of this object
    /// </summary>
    public MsnObjectType Type
    {
      get { return _type; }
      set { _type = value; }
    }

    /// <summary>
    /// Gets or sets the content hash of this object
    /// </summary>
    public string SHA1C
    {
      get { return _sha1c; }
    }

    /// <summary>
    /// Gets or sets the data hash of this object
    /// </summary>
    public string SHA1D
    {
      get { return _sha1d; }
      set { _sha1d = value; }
    }

    public int Size
    {
      get { return _size; }
      set { _size = value; }
    }
    #endregion

    public void ComputeContentHash()
    {
      string content = String.Format("Creator{0}Size{1}Type{2}Location{3}Friendly{4}SHA1D{5}",
          this.Creator,
          this.Size, (int)this.Type,
          this.Location, this.Friendly, this.SHA1D);

      byte[] digest = SHA1CryptoServiceProvider.Create().ComputeHash(Encoding.ASCII.GetBytes(content));
      _sha1c = Convert.ToBase64String(digest);
    }

    public override string ToString()
    {
      return String.Format("<msnobj Creator=\"{0}\" Size=\"{1}\" Type=\"{2}\" " +
						  "Location=\"{3}\" Friendly=\"{4}\" SHA1D=\"{5}\" " +
						  "SHA1C=\"{6}\"/>",
						  this.Creator,
						  this.Size,
						  (int)this.Type,
						  this.Location,
						  this.Friendly,
						  this.SHA1D, this.SHA1C);
    }
  }
}
